//Author: bishisimo
//Time: 2021/7/12 上午9:22
//Describe:
package console

import (
	"bytes"
	"fmt"
	"gitee.com/bishisimo/log-parser/model"
	"os"
	"regexp"
	"sort"
	"strings"
)

var DefaultConsole *simpleParser

func init() {
	DefaultConsole = &simpleParser{
		traceReg: regexp.MustCompile(`.*TRACE?.*`),
		debugReg: regexp.MustCompile(`.*DEBUG?.*`),
		infoReg:  regexp.MustCompile(`.*INFO.*`),
		warnReg:  regexp.MustCompile(`.*WARN.*`),
		errorReg: regexp.MustCompile(`.*ERROR?.*`),
		fatalReg: regexp.MustCompile(`.*FATAL?.*`),
	}
}

type simpleParser struct {
	traceReg *regexp.Regexp
	debugReg *regexp.Regexp
	infoReg  *regexp.Regexp
	warnReg  *regexp.Regexp
	errorReg *regexp.Regexp
	fatalReg *regexp.Regexp
}

func (p simpleParser) Write(raw []byte) (int, error) {
	lever := p.ParserLever(raw)
	c := p.ColorLever(lever)
	buf := consoleBufPool.Get().(*bytes.Buffer)
	defer consoleBufPool.Put(buf)
	fmt.Fprintf(buf, "%s",
		model.Colorize(string(raw), c, true))
	buf.WriteByte('\n')
	n, err := buf.WriteTo(os.Stdout)
	return int(n), err
}

func (p simpleParser) ParserLever(msg []byte) string {
	locMap := make(map[int]string)
	i := p.traceReg.FindIndex(msg)
	if i != nil {
		locMap[i[0]] = "TRACE"
	}
	i = p.debugReg.FindIndex(msg)
	if i != nil {
		locMap[i[0]] = "DEBUG"
	}
	i = p.infoReg.FindIndex(msg)
	if i != nil {
		locMap[i[0]] = "INFO"
	}
	i = p.warnReg.FindIndex(msg)
	if i != nil {
		locMap[i[0]] = "WARN"
	}
	i = p.errorReg.FindIndex(msg)
	if i != nil {
		locMap[i[0]] = "ERROR"
	}
	i = p.fatalReg.FindIndex(msg)
	if i != nil {
		locMap[i[0]] = "FATAL"
	}
	if len(locMap) == 0 {
		return ""
	}
	locList := make([]int, 0)
	for k := range locMap {
		locList = append(locList, k)
	}
	sort.Ints(locList)
	return locMap[locList[0]]
}

func (p simpleParser) ColorLever(lever string) int {
	switch strings.ToUpper(lever) {
	case "TRAC", "TRACE":
		return model.CCyan
	case "DEBU", "DEBUG":
		return model.CCyan
	case "INFO":
		return model.CGreen
	case "WARN":
		return model.CYellow
	case "ERRO", "ERROR", "FATA", "FATAL", "PANI", "PANIC":
		return model.CRed
	default:
		return model.CReset
	}
}
